import os

from PyQt4 import QtCore, QtGui

from limber.viewdisplayers import tabbedviewdisplayer
from limber.ui.mainwindow import MainWindow
from limber.ui.dialogs import get_dialog
from limber.ui import events
from limber import componentmanager
from limber import documentmanager
from limber import viewmanager
from limber import abilities
from limber import utils


class ApplicationError(Exception):
    '''Exception raised by the *Application* object.'''
    
    pass


def instance(raise_exception=False):
    '''Return the *Application* instance or `None`.
    
    If *raise_exception* is `True`, than
    *ApplicationError* is raised if no instance can
    be found.
    
    `None` is returned also if the `QCoreApplication`
    is not an *Application* instance.
    '''
    
    inst = QtCore.QCoreApplication.instance()
    if raise_exception and inst is None:
        raise ApplicationError('There is no Application\'s instance avaiable.')
    elif not isinstance(inst, Application):
        return None
    return inst


class Application(QtGui.QApplication):
    '''The LimberEditor application.'''

    def __init__(self, userdir=None, systemdir=None):
        super(Application, self).__init__([])

        if userdir is not None:
            self._userdir = userdir
        else:
            self._userdir = os.path.expanduser('~/.limber')

        if systemdir is not None:
            self._systemdir = systemdir
        else:
            self._systemdir = '/usr/share/limber'

        if not os.path.exists(self._userdir):
            try:
                utils.create_userdir(self._userdir)
            except (IOError, OSError), e:
                utils.info('Could not create the user directory: %r' % e)

        if not os.path.exists(self._systemdir):
            try:
                utils.create_systemdir(self._systemdir)
            except (IOError, OSError), e:
                utils.info('Could not create the system directory: %r' % e)
        
        self._componentmanager = componentmanager.ComponentManager(self)
        self._componentmanager.load_builtin_components()
        displayer_class = self._componentmanager.get_viewdisplayer('tabbedviewdisplayer')
        
        self._mainwindow = MainWindow(None, viewdisplayer=displayer_class)

        self._displayer = self._mainwindow.viewdisplayer
        self._viewmanager = viewmanager.ViewManager(self, self._displayer)
        self._documentmanager = documentmanager.DocumentManager(self,
                                                                self._viewmanager)
        
        self._closing = False
        
        self._init_connections()

    def _init_connections(self):
        '''Initializes all the connections between objects.'''
        
        self._mainwindow.application_closure_request.connect(
                        self.handle_application_closure_request)
        self._mainwindow.create_new_document_request.connect(
                        self.handle_create_new_document_request)
        self._mainwindow.close_current_document_request.connect(
                        self.handle_close_current_document_request)
    
    @property
    def mainwindow(self):
        '''The application's mainwindow.'''

        return self._mainwindow

    @property
    def componentmanager(self):
        '''The application's componentmanager.'''

        return self._componentmanager

    @property
    def viewmanager(self):
        '''The application's viewmanager.'''

        return self._viewmanager

    @property
    def documentmanager(self):
        '''The application's documentmanger.'''

        return self._documentmanager

    def userdir_path(self):
        '''Return the path to the user directory.'''

        return self._userdir

    def systemdir_path(self):
        '''Return the path to the system directory.'''

        return self._systemdir
    
    def is_shuttingdown(self):
        '''Return `True` if the application is shuttingdown.'''
        
        return self._closing
    
    def query_save_filename(self, document):
        '''Query a filename to the user.'''

        doc_path = document.path()
        if doc_path is None:
            curdir = os.getcwd()
        else:
            curdir = os.path.dirname(doc_path)

        dlg = get_dialog('query-save-filename')(self._mainwindow)
        if dlg.exec_():
            return dlg.filename
        else:
            #Mmm, this should be changed I think...
            return False

    def query_close_document(self, document):
        '''Return True if the user wants to close *document*.'''

        dlg = get_dialog('query-close-document')(self._mainwindow)
        if dlg.exec_():
            return dlg.close_document
        else:
            return False

    def query_discard_document(self, document):
        '''Return True if the user wants to discard changes of *document*.'''

        dlg = get_dialog('query-discard-document')(self._mainwindow)
        if dlg.exec_():
            return dlg.discard_document
        else:
            return False
    
    def avaiable_abilities(self):
        '''Return the avaiable abilities names.'''
        
        return iter(abilities.ABILITIES.keys())
    
    def exec_(self, show=True):
        '''Shows the mainwindow and runs the mainloop.'''

        if show:
            self._mainwindow.show()

        return super(Application, self).exec_()
    
    #Methods called by signals.
    def handle_create_new_document_request(self):
        '''Handles the signal *createNewDocumentRequest*.'''
        
        print 'signal "createNewDocumentRequest" received'
        #dlg_class = get_dialog('create-new-document')
        
    
    def handle_close_current_document_request(self):
        '''Handles the signal *closeCurrentDocumentRequest*.'''
        
        print 'signal "closeCurrentDocumentRequest" received'
    
    def handle_application_closure_request(self):
        '''Handles the signal *applicationClosureRequest*.'''
        
        self._closing = True
        event = events.CloseEvent()
        event.must_close = True
        if self.notify(self._mainwindow, event):
            self.quit()
